package com.dodo.blog.server.impl;

import com.comvai.auth.exception.AuthenticatedException;
import com.comvai.auth.model.AuthUser;
import com.comvai.auth.model.LoginProperties;
import com.comvai.auth.model.SessionUser;
import com.comvai.auth.server.AuthService;
import com.comvai.auth.util.LoginPropertiesParser;
import com.comvai.services.cache.CacheService;
import com.comvai.services.persistence.LowLevel;
import com.comvai.services.persistence.PersistenceManager;
import com.comvai.services.persistence.criteria.Criteria;
import com.comvai.services.persistence.criteria.Restrictions;
import com.dodo.blog.exception.UserNotFoundForEmail;
import com.dodo.blog.exception.UserNotFoundForLogin;
import com.dodo.blog.model.Account;
import net.sf.jsr107cache.Cache;
import org.apache.commons.codec.digest.DigestUtils;

import javax.inject.Inject;
import java.io.IOException;
import java.util.List;

/**
 * @author <a href="mailto:pohorelec@comvai.com">Jozef Pohorelec</a>
 */
public class AuthServiceBean
        extends AbstractServiceBean
        implements AuthService
{
    private static final String LOGIN_PROPERTIES_PATH = "/com/dodo/blog/server/impl/LoginProperties.properties";

    private String LOGIN_PROPERTIES_CACHE_NAMESPACE = "login_properties_memcache";

    private String LOGIN_PROPERTIES_CACHE_KEY = "login_properties_key";

    private Cache cache;

    @Inject
    public AuthServiceBean( @LowLevel PersistenceManager datastore, CacheService memcache )
    {
        super( datastore );

        cache = memcache.create( LOGIN_PROPERTIES_CACHE_NAMESPACE );
        cache.clear();
    }

    @Override
    public AuthUser authenticate( SessionUser sessionUser ) throws AuthenticatedException
    {
        Account account = null;

        switch ( sessionUser.getLoginType() )
        {
            case OAUTH:
            case OPEN_ID:
            {
                String email = sessionUser.getEmail();
                Criteria<Account> criteria = Criteria.create( Account.class );
                criteria.addCriteria( Restrictions.eq( "email", email ) );

                List<Account> list = datastore.list( criteria );
                if ( list.size() > 0 )
                {
                    account = list.get( 0 );
                }
                else
                {
                    log.info( "User not found for email: " + email );
                    throw new UserNotFoundForEmail();
                }

                break;
            }
            case LOGIN:
            {
                String login = sessionUser.getLogin();
                String password = sessionUser.getPassword();
                Criteria<Account> criteria = Criteria.create( Account.class );
                criteria.addCriteria( Restrictions.eq( "login", login ) );
                criteria.addCriteria( Restrictions.eq( "password", DigestUtils.md5Hex( password ) ) );

                List<Account> list = datastore.list( criteria );
                if ( list.size() > 0 )
                {
                    account = list.get( 0 );
                }
                else
                {
                    log.info( "User not found for login: " + login );
                    throw new UserNotFoundForLogin();
                }

                break;
            }
        }

        return account;
    }

    @Override
    public AuthUser getAuthUserById( String authUserId )
    {
        Account account = datastore.find( Account.class, Long.valueOf( authUserId ) );

        if ( account == null )
        {
            log.info( "Account not found for id: " + authUserId );
        }

        return account;
    }

    @Override
    public LoginProperties getLoginProperties( String domainName )
    {
        if ( cache.containsKey( LOGIN_PROPERTIES_CACHE_KEY ) )
        {
            return ( LoginProperties ) cache.get( LOGIN_PROPERTIES_CACHE_KEY );
        }

        LoginProperties properties = null;

        try
        {
            LoginPropertiesParser parser = new LoginPropertiesParser( AuthServiceBean.class.getResourceAsStream( LOGIN_PROPERTIES_PATH ) );
            properties = parser.get( domainName );

            cache.put( LOGIN_PROPERTIES_CACHE_KEY, properties );
        }
        catch ( IOException e )
        {
            log.severe( "Error occurred during loading LoginProperties: " + e );
        }

        return properties;
    }
}